# !/usr/bin/env python
# -*- coding: utf-8 -*-
# Author : hysia
# Filename: redirectck.py
# Ver : 1.1
# Last update: 2010-09-08

"""
网页跳转检测模块
通过对传入URL跳转的识别，获取到跳转后真实的URL地址
1.meta refresh自动跳转法
例如：<meta http-equiv="refresh" content="10;url=http://www.example.com/">

2.服务端跳转法
例如：response.redirect() 、server.transfer() 等

3.body onload自动跳转法
例如：<body onload="parent.location='http://www.example.com'">

4.javascript自动跳转法(复杂)
window.location.href = "value"
window.location = "value"
window.location.replace("value")
window.location.assign("value")
例如：<script language="javascript">location.replace("http://www.example.com")</script>
<script language="javascript">window.location="http://www.example.com";</script>
<script language="javascript">window.location.href="http://www.example.com";</script>

5.Flash跳转法

"""
import re
import urllib2 
from kscomm.jsdecode.jsrun import *

########################################################################
class Redirectck:
	"""
	跳转检测的类
	"""

	#----------------------------------------------------------------------
	def __init__(self,sURL):
		"""
		_sURL表示原始URL地址
		_dURL表示跳转的目标URL地址
		_method表示跳转方法，比如：META，REDIRECT, JAVASCRIPT, SWF ... etc
		_urls 表示跳转的URL列表
		"""
		self.set_env()
		self._sURL = sURL
		self._code = None
		self._red_url = None
		self._page_content = self.get_page(sURL)
		
	def get_page(self,url):
		"""function to get the content of the web page.return the string page content"""
		try:
			request = urllib2.Request(url)
			#import pdb;pdb.set_trace()
			opener = urllib2.build_opener(SmartRedirectHandler())
			webpage = opener.open(request)
			#print webpage.code
			self._code = webpage.code
			self._red_url = webpage.url
			page_content = webpage.read()
			opener.close
		except:
			page_content = "read webpage error!"
		
		return page_content
	
	def set_sURL( self ,url):
		"""设置原始URL地址"""
		self._sURL = url
		
	def set_dURL(self,url):
		"""设置跳转URL地址"""
		self._dURL = url
		
	def set_method(self,method):
		"""设置跳转方法"""
		self._method = method

	def set_urls(self,urls):
		"""设置跳转URL列表"""
		self._urls = urls

	def set_jump(self,isjump):
		self.isjump = isjump

	def set_env(self):
		"""初始化内部变量"""	
		self.set_dURL(url=None)
		self.set_method(method=None)
		self.set_urls(urls=[])
		self.set_jump(isjump=False)
		
	def meta_check(self):
		"""META跳转检测方法"""
		self.set_env()
		meta_tags = re.compile('(?is)\<meta[^<>]*?url\s*=([\d\w://\\\\.?=&;%-]*)[^<>]*')
		self._urls = meta_tags.findall(self._page_content)
		if self._urls:
			self.set_dURL(self._urls[-1])
		if self._dURL:
			self.set_method('META')
			self.set_jump(True)
			
	def server_check(self):
		"""服务端跳转检测"""
		self.set_env()
		if not self._code == 200:
			self.set_dURL(self._red_url)
		if self._dURL:
			self.set_method('SERVER '+ str(self._code) )
			self.set_jump(True)

	def onload_check(self):
		""" BODY ONLOAD跳转检测方法"""
		self.set_env()
		onload_url = re.compile(r'''(?is)\<body[^<>]*?location\s*=['"]?([\d\w://\\\\.?=&;%-]*)['"]?[^<>]*''')
		self._urls = onload_url.findall(self._page_content)
		if self._urls:
			self.set_dURL(self._urls[-1])
		if self._dURL:
			self.set_method('ONLOAD')
			self.set_jump(True)
	
	def js_check(self):
		"""JAVASCRIPT跳转检测方法
		JAVASCRIPT跳转中核心的调用方法是利用浏览器的location对象通过对location、location.href、location.replace()、location.assign()的操作
		实现跳转，跳转路径可能是相对路径或绝对路径
		现在使用的方法是用jsunpack 的修改模块执行js 获取最真实的跳转！
		"""
		self.set_env()
		js = JSDecode(config_file_dir="/opt/kscomm/jsdecode",timeout=10)
		js.debug=0
		decoded,jstime,errors = js.decodeHtml(self._page_content,url=self._sURL)
		#decoded,jstime,errors = js.decodeJS(self._page_contenti,url='')
		self._urls = js.find_urls(decoded)
		if self._urls:
			self.set_dURL(self._urls[-1])
		if self._dURL:
			self.set_method('JAVASCRIPT')
			self.set_jump(True)

	def swf_check(self):
		"""检测falsh跳转需要使用flare反编译flash文件得到AS代码后通过正则匹配查找跳转后的URL"""
		pass

	def check(self):
        	self.server_check()
		if not self.isjump:
			self.meta_check()
			if not self.isjump:
				self.onload_check()
				if not self.isjump:
					self.js_check()
		#print u'跳转URL : %s' %(self._dURL)
		#print u'跳转方法：%s' %(self._method)
		#print u'跳转URL列表：%s' %(self._urls)
		#print u'是否跳转：%s' %(self.isjump)
		#print self._page_content
		return (self._method, self._urls)

#############################################################################

class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
	def http_error_301(self, req, fp, code, msg, headers):
		result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)
		result.code = code
		return result

	def http_error_302(self, req, fp, code, msg, headers):
		result = urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
		#result.status = code
		result.code = code
		return result

#############################################################################
"""
单文件自测试
"""
def jumpcheck(url):
	jc = Redirectck(url)
	jc.server_check()
	if not jc.isjump:
		jc.meta_check()
		if not jc.isjump:
			jc.onload_check()
			if not jc.isjump:
				jc.js_check()

	print u'原始URL : %s'  %(jc._sURL)
	print u'跳转URL : %s' %(jc._dURL)
	print u'跳转方法：%s' %(jc._method)
	print u'跳转URL列表：%s' %(jc._urls)
	print u'是否跳转：%s' %(jc.isjump)
	#print jc._page_content



if __name__ =='__main__':
	import sys
	sURL = sys.argv[1]
	#rc = Redirectck(sURL='http://www.customs.gov.cn')
	#rc = Redirectck(sURL='http://www.googe.com')
	jumpcheck(sURL)	
